/**
 * @file ObservationsListDialog.cpp
 *
 * Klasa okna przeglądania obserwacji - implementacja.
 *
 * @author Zbigniew Siciarz
 * @date 2009
 * @version 2.0.0
 * @since 2.0.0
 */

#include "ObservationsListDialog.h"
#include "dogz/JdTools.h"
#include "dogz/ObservationManager.h"
#include "dogz/OutputWriterFactory.h"
#include "MessageDialog.h"
#include <QApplication>
#include <QHeaderView>
#include <QMessageBox>
#include <QtSql>
#include <QVector>

using Dogz::ObservationManager;

/**
 * Konstruktor okienka listy obserwacji.
 *
 * Tworzy GUI oraz model, przypisuje model do widoku tabelarycznego i łączy
 * sygnał selectionChanged() modelu ze slotem okna.
 *
 * @param parent obiekt rodzica
 */
ObservationsListDialog::ObservationsListDialog(Dogz::StarManager* mgr,
        QWidget *parent)
    : QDialog(parent), model(0), lastSearchByStar(false), plotWindow(0), m_mgr(mgr)
{
	ui.setupUi(this);

	model = new ObservationModel(this);

    ui.tblObervations->setModel(model);
    ui.tblObervations->setColumnHidden(ObservationManager::Id, true);
    ui.tblObervations->setColumnHidden(ObservationManager::FainterThan, true);

    QHeaderView* header = ui.tblObervations->horizontalHeader();
    header->setDefaultAlignment(Qt::AlignCenter);
    header->setSortIndicator(ObservationManager::Jd, Qt::DescendingOrder);
    header->setStretchLastSection(true);

    ui.editDateTo->setDate(QDate::currentDate());
    // TODO: odczytać z ustawień
    ui.editDateFrom->setDate(QDate::currentDate().addDays(-14));

    connect(ui.tblObervations->selectionModel(),
            SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
            this,
            SLOT(updateSelection(const QItemSelection&, const QItemSelection&))
    );
}

/**
 * Zdarzenie wyświetlenia okna - ustawia filtr "wszystkoprzepustowy".
 */
void ObservationsListDialog::showEvent(QShowEvent* event)
{
    doSelect("jd > 0.0");
}

/**
 * Reakcja na zmianę opcji w comboboxie z datą obserwacji (cbxDateType).
 *
 * @param index numer pozycji w comboboxie
 */
void ObservationsListDialog::on_cbxDateType_currentIndexChanged(int index)
{
    if (2 == index) // TODO: pozbyć się tej "magicznej liczby"
    {
        ui.editDateFrom->setEnabled(true);
        ui.editDateTo->setEnabled(true);
    }
    else
    {
        ui.editDateFrom->setEnabled(false);
        ui.editDateTo->setEnabled(false);
    }
}

/**
 * Slot przycisku "Wyświetl" - przygotowuje filtrowanie listy obserwacji.
 *
 * Jeśli zostało coś wpisane do pola na ręczny warunek zapytania, to przyjmuje
 * to za filtr i przechodzi od razu do wywołania doSelect(). W przeciwnym razie
 * sprawdza, którą opcję wybrano w comboboxie i zależnie od tego ustala
 * początkowe i końcowe wartości JD.
 */
void ObservationsListDialog::on_btnShow_clicked()
{
    QString filter;
    if (!ui.editQuery->text().isEmpty())
    {
        filter = ui.editQuery->text();
    }
    else
    {
        // wyszukiwanie w przedziale daty
        double jdFrom = 0.0, jdTo = 0.0;
        switch (ui.cbxDateType->currentIndex())
        {
        // dziś
        case 0:
            jdTo = JdTools::currentJd();
            jdFrom = jdTo - 1;
            break;
        // wczoraj
        case 1:
            jdTo = JdTools::currentJd() - 1;
            jdFrom = jdTo - 1;
            break;
        // od-do
        case 2:
            jdFrom = JdTools::dateToJd(ui.editDateFrom->dateTime());
            jdTo = JdTools::dateToJd(ui.editDateTo->dateTime());
            break;
        }
        filter = QString("jd BETWEEN %1 AND %2").arg(jdFrom, 0, 'f', 4).
            arg(jdTo , 0, 'f', 4);

        if (ui.starName->text().isEmpty())
        {
        	lastSearchByStar = false;
        }
        else
        {
            QString starName = Dogz::Star::normalizeStarName(ui.starName->text());

        	if (!filter.isEmpty())
        		filter += QString(" AND star_name='%1'").arg(starName);
        	else
        		filter = QString("star_name='%1'").arg(starName);

        	lastSearchByStar = true;
        }
    }

    doSelect(filter);
}

/**
 * Wyświetla wszystkie obserwacje, resetując ewentualne filtry.
 */
void ObservationsListDialog::on_btnReset_clicked()
{
    ui.starName->clear();
    doSelect("jd > 0.0");
}

/**
 * Wyświetla okno generatora wykresów.
 */
void ObservationsListDialog::on_btnPlot_clicked()
{

	if (!lastSearchByStar){
		QMessageBox::warning(this, tr("DOGZ"),
				tr("Generacja wykresu ma sens tylko dla określonej gwiazdy. "
						"Wyszukaj obserwacje wprowadzając nazwę gwiazdy w odpowiednie pole."));
		return;
	}

	QVector<Dogz::VisualObservation> obsVector;

	if (!plotWindow)
	{
		plotWindow = new PlotWindow(m_mgr, this);
	}

	// przekazujemy obserwacje, ktore beda wykorzystane do generacji wykresu
	// pobieramy listę wierszy i sortujemy rosnąco
	QModelIndexList rows = ui.tblObervations->selectionModel()->selectedRows(1);

    if (rows.isEmpty()){
        QMessageBox::warning(this, tr("Wybierz obserwacje!"),
                tr("Zaznacz przynajmniej jedna obserwacje. "));
        return;
    }

	qSort(rows.begin(), rows.end(), qGreater<QModelIndex>());

	foreach (QModelIndex rowIndex, rows)
	{
	    // tworzenie obserwacji na podst. indeksu zostało przeniesione do managera
	    obsVector.push_back(ObservationManager::getByModelIndex(rowIndex));
	}

	plotWindow->setData(obsVector);
	//pokazujemy okienko
	plotWindow->show();
	plotWindow->raise();
	plotWindow->activateWindow();
}

/**
 * Wykonuje właściwe pobieranie listy obserwacji z bazy, uwzględniając filtr.
 *
 * Przekazuje podany parametr do metody setFilter() modelu, wczytuje wszystkie
 * wiersze, oraz podaje ich liczbę (tabela wypełnia się automatycznie). Podczas
 * operacji kursor ma kształt strzałki z klepsydrą.
 *
 * @param filter filtr w postaci warunku WHERE zapytania
 */
void ObservationsListDialog::doSelect(const QString& filter)
{
    QApplication::setOverrideCursor(Qt::BusyCursor);

    model->setFilter(filter);
    if (!model->select())
    {
        MessageDialog::showInformation(tr("DOGZ"), tr("Błąd bazy danych: %1").
                arg(model->lastError().text()));
        QApplication::restoreOverrideCursor();
        return;
    }

    // brzydka metoda na uzyskanie poprawnej liczby wierszy... ale działa
    while (model->canFetchMore())
        model->fetchMore();

    ui.lblModelInfo->setText(tr("Znaleziono %1 obserwacji.").arg(model->rowCount()));

    ui.tblObervations->resizeColumnsToContents();
    ui.tblObervations->resizeRowsToContents();

    QApplication::restoreOverrideCursor();
}

/**
 * Ustawia zaznaczenie tabeli na wszystkie widoczne wiersze.
 *
 * @TODO: pozbyć się magicznych numerków
 */
void ObservationsListDialog::on_btnSelectAll_clicked()
{
    QItemSelectionModel* selectionModel = ui.tblObervations->selectionModel();
    QModelIndex topLeft = ui.tblObervations->model()->index(0, 1);
    QModelIndex bottomRight = ui.tblObervations->model()->index(model->rowCount()-1, 8);
    selectionModel->select(QItemSelection(topLeft, bottomRight),
            QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}

/**
 * Slot przycisku "Eksportuj" (...zaznaczone obserwacje).
 *
 * Pobiera i sortuje rosnąco listę wierszy, następnie próbuje utworzyć obiekt
 * formatujący zapis na podstawie wybranej pozycji comboboxa. Dodaje kolejne
 * obserwacje do zapisywarki, a potem wyrzuca jej wyjście do textedita.
 */
void ObservationsListDialog::on_btnExport_clicked()
{
    // pobieramy listę wierszy i sortujemy rosnąco
    QModelIndexList rows = ui.tblObervations->selectionModel()->selectedRows(1);
    qSort(rows.begin(), rows.end(), qGreater<QModelIndex>());

    try
    {
        Dogz::OutputWriter* out =
            Dogz::OutputWriterFactory::getWriter(ui.cbxExport->currentText());

        foreach (QModelIndex rowIndex, rows)
        {
            out->addObservation(ObservationManager::getByModelIndex(rowIndex));
            ui.editOutput->setPlainText(out->getOutput());
        }
    }
    catch (Dogz::Exception& e)
    {
        QMessageBox::information(this, tr("DOGZ"), e.what());
    }
}

/**
 * Slot podłączony do zdarzenia zmiany zaznaczenia w modelu.
 *
 * Informuje o liczbie zaznaczonych wierszy.
 */
void ObservationsListDialog::updateSelection(const QItemSelection&, const QItemSelection&)
{
    QModelIndexList rows = ui.tblObervations->selectionModel()->selectedRows(1);
    ui.gbxSelection->setTitle(tr("Zaznaczenie (%1 obserwacji)").
            arg(rows.size()));
}
